/*
 *
 *
 */
#include <string.h>
#include "gkt_debug.h"
#include "gkt_board.h"
#include "gkt_wakeup.h"
#include "gkt_window.h"
#include "gkt_bg_job.h"
#include "key_common.h"

#if defined (GKT_CONFIG_KEYPAD_ENABLE) && GKT_CONFIG_KEYPAD_ENABLE

key_manage_s g_key_manage;

#ifdef GKT_CONFIG_KEY_MAP_TABLE
__RETMEM_SYS uint8_t key_calibrate_fail=0;

#if 0
#define GKT_KEY_MAP(key_name)	GKT_KEY_##key_name
static const uint32_t sc_key_map_table[] = {
	GKT_CONFIG_KEY_MAP_TABLE
};
static const uint32_t sc_key_map_table_size = 
			sizeof(sc_key_map_table) / sizeof(uint32_t);

#define channel_2_key(channel)	\
	(((channel) < sc_key_map_table_size) ? \
		sc_key_map_table[channel] : GKT_KEY_MAX)
#endif

uint8_t key_used=0;
static void key_notify(gkt_keypad_keyinfo_s *keyinfo)
{
	gkt_event_s event;
	uint32_t key;

	if (keyinfo) {
		key = channel_2_key(keyinfo->channel);
#if defined(GKT_CONFIG_KEY_PRINT) && GKT_CONFIG_KEY_PRINT		
		gkt_printf("ch=%d key=%d action=%d\n",keyinfo->channel, key,keyinfo->action);
#endif
		if (key < GKT_KEY_MAX) {
			if (GKT_KEY_ACTION_LONG_PRESS == keyinfo->action) {
				key_used = 1;
				if (keyinfo->repeat_count == 1) {
					keyinfo->repeat_count = 0;
					gkt_keypad_update_base_freqs();
				}
			}
			if (GKT_KEY_ACTION_SHORT_PRESS == keyinfo->action) {
				key_used = 1;
			}

			if (((GKT_KEY_ACTION_LONG_PRESS == keyinfo->action)
					|| (GKT_KEY_ACTION_RELEASE == keyinfo->action))
				&& !(g_key_manage.long_press_bits & (1U << key)))
			{
				return;
			}

			event.window_id = GKT_WINDOW_ID_ACTIVE;
			event.flags = 0;
			event.major_type = GKT_EVENT_KEY;
			event.minor_type = (uint16_t)key;
			event.data[GKT_KEY_EVTDATA_ACTION] = keyinfo->action;
			event.data[GKT_KEY_EVTDATA_REPEAT] = keyinfo->repeat_count;
			gkt_event_put(&event, GKT_IMMEDIATELY);
		}
		else
			gkt_info("key_notify: unrecognized key - %u\n", key);
	}
	else
		GKT_ASSERT(0);
}

#else

#define channel_2_key(channel)	(channel)

static void key_notify(gkt_keypad_keyinfo_s *keyinfo)
{
	gkt_event_s event;

	if (keyinfo 
		&& (keyinfo->channel < GKT_KEY_MAX)) 
	{
		event.window_id = GKT_WINDOW_ID_ACTIVE;
		event.flags = 0;
		event.major_type = GKT_EVENT_KEY;
		event.minor_type = (uint16_t)keyinfo->channel;
		event.data[GKT_KEY_EVTDATA_ACTION] = keyinfo->action;
		event.data[GKT_KEY_EVTDATA_REPEAT] = keyinfo->repeat_count;
		gkt_event_put(&event, GKT_IMMEDIATELY);
	}
	else
		GKT_ASSERT(0);
}

#endif

static void key_RETURN_def_handler(uint32_t *evt_data)
{
	gkt_unused(evt_data);
	gkt_window_show(GKT_WINDOW_ID_PREVIOUS, 0);
}

void gkt_key_register_default_handler(uint32_t key,
			gkt_key_default_handler def_handler)
{
	if (key< GKT_KEY_MAX)
		g_key_manage.def_handlers[key] = def_handler;
}

static int gkt_key_event_handler(gkt_event_s *event)
{
	gkt_window_s *window;
	int retval;

	if (event->minor_type < GKT_KEY_MAX) {
		window = gkt_window_find(GKT_WINDOW_ID_ACTIVE);
		if (__UNLIKELY(!window)) {
			gkt_error("key_event_handler: active window NULL!\n");
			return GKT_EVENT_HANDLE_COMPLETE;
		}
		
		if (!(g_key_manage.flags & KEY_F_FIRST_VALID)) {
			/*
			 *  one key is pressed at previous window & not release 
			 *  after current window is showed, then this key event
			 *  is ignored.
			 */
			if (event->data[GKT_KEY_EVTDATA_ACTION] != GKT_KEY_ACTION_SHORT_PRESS)
				return GKT_EVENT_HANDLE_COMPLETE;
			g_key_manage.flags |= KEY_F_FIRST_VALID;
		}

		if (g_key_manage.unmask_bits & (1U << event->minor_type)) {
			if (!(event->flags & GKT_EVENT_F_STAGED))
				key_voice_play(event->minor_type, GKT_KEY_VOICE_VALID);

			if (window->widget_focus) {
				/* let focus widget process the key event firstly */
				retval = gkt_widget_event_dispatch(window->widget_focus,
								event->major_type, event->minor_type, 
								(uint32_t)event->data);
				if (retval < GKT_EVENT_HANDLE_CONTINUE) {
					if (GKT_EVENT_HANDLE_STAGE == retval)
						gkt_event_stage(event);
					return retval;
				}
			}

			/* let custom window event handler process the key event */
			retval = gkt_window_custom_event_handle(window, 
							event->major_type, event->minor_type, 
							0, (uint32_t)event->data);
			if (retval < GKT_EVENT_HANDLE_CONTINUE) {
				if (GKT_EVENT_HANDLE_STAGE == retval)
					gkt_event_stage(event);
				return retval;
			}

			/* default process */
			if (g_key_manage.def_handlers[event->minor_type])
				(*g_key_manage.def_handlers[event->minor_type])(event->data);
		}
		else
			key_voice_play(event->minor_type, GKT_KEY_VOICE_INVALID);
	}
#if GKT_KEY_LED_FLICKER_ENABLE
	else if (GKT_KEY_MINOR_LED_FLICKER_END == event->minor_type) {
		window = gkt_window_find(event->window_id);
		if (window) {
			gkt_window_custom_event_handle(window, 
					event->major_type, event->minor_type, 
					0, 0);
		}
	}
#endif

	return GKT_EVENT_HANDLE_COMPLETE;
}

void gkt_key_get_unmask_bits(uint32_t *unmask_bits)
{
#if (GKT_KEY_MAX <= 32)
	if (unmask_bits)
		*unmask_bits = g_key_manage.unmask_bits;
#endif
}

void gkt_key_reset(void)
{
	g_key_manage.flags &= ~KEY_F_FIRST_VALID;
	g_key_manage.long_press_bits = 0;
	gkt_key_voice_mask(0);
}

void gkt_key_mask(int masked, uint32_t flags)
{
	uint32_t key_bits;

	if (masked) {
		gkt_keypad_control(GKT_KEYPAD_CTRL_DISABLE, 0);
		key_bits = (flags & GKT_KEY_MASK_F_LED_DETACH) ?
			g_key_manage.unmask_bits : 0;
	}
	else {
		gkt_keypad_control(GKT_KEYPAD_CTRL_ENABLE, 0);
		key_bits = g_key_manage.unmask_bits;
	}
	gkt_key_led_control(GKT_KEY_LED_CTRL_BRIGHT, key_bits);
}

void gkt_key_mask_partial(uint32_t masked_bits)
{
	/* update key bits */
	g_key_manage.unmask_bits = ~masked_bits & ((1U << GKT_KEY_MAX) - 1);
	gkt_key_led_control(GKT_KEY_LED_CTRL_BRIGHT, g_key_manage.unmask_bits);
}

void gkt_key_stage(uint16_t key_value, uint32_t data)
{
	uint32_t *event_data = (uint32_t *)data;
	gkt_event_s event;

	event.window_id = GKT_WINDOW_ID_ACTIVE;
	event.flags = 0;
	event.major_type = GKT_EVENT_KEY;
	event.minor_type = key_value;
	event.data[GKT_KEY_EVTDATA_ACTION] = event_data[GKT_KEY_EVTDATA_ACTION];
	event.data[GKT_KEY_EVTDATA_REPEAT] = event_data[GKT_KEY_EVTDATA_REPEAT];
	gkt_event_stage(&event);
}

/************************************************************
* BPK Key:A total of 32 Uint32_t 
*		  uint32_t [0~2] description:gkt_retmem.h
*		  uint32_t [3]:keypad used
*			   Byte[0]:Record how many key chips are used 12/15
*			   Byte[1]:Record keypad calibration has failed
************************************************************/
static void key_calibrate(uint32_t status)
{
	int retval;
	uint32_t value;
	
	//gkt_keypad_control(GKT_KEYPAD_CTRL_ENABLE, 0);

	g_key_manage.flags &= ~KEY_F_CALIBRATE_DONE;

	g_key_manage.flags |= KEY_F_CALIBRATE_BUSY;
	
#if defined(GKT_CONFIG_KEY_WAKEUP_NO_CALIBRATE) && GKT_CONFIG_KEY_WAKEUP_NO_CALIBRATE	
	if ((GKT_SYSTEM_RESET_WAKEUP == g_system_info.reset_mode) 
		&& (status != GKT_KEYPAD_CALIBRATE_STANDBY)) {
		if ((GKT_WAKEUP_SRC_keypad == gkt_wakeup_get_source())
			|| (GKT_WAKEUP_SRC_rfid == gkt_wakeup_get_source()))	
			retval = gkt_key_wakeup_resume_parameter();
		else
			retval = gkt_keypad_calibrate(1, status);
	}
	else
		retval = gkt_keypad_calibrate(1, status);
#else
	retval = gkt_keypad_calibrate(1, status);
#endif
		
	g_key_manage.flags &= ~KEY_F_CALIBRATE_BUSY;

	if (GKT_SUCCESS == retval) {
		g_key_manage.flags |= KEY_F_CALIBRATE_DONE;
		key_calibrate_fail = 0;
	}
	else {
		gkt_printf("!keypad used baseup value\n");
		g_key_manage.flags |= KEY_F_CALIBRATE_DONE;
		key_calibrate_fail = 1;
		gkt_key_wakeup_resume_parameter();
	}

	G_BPK_ReadKey(&value, 1, GKT_RETMEM_KEYPAD);
	value &= 0xFFFF00FF;
	value |= key_calibrate_fail << 8;	
	G_BPK_WriteKey(&value, 1, GKT_RETMEM_KEYPAD);
	gkt_keypad_control(GKT_KEYPAD_CTRL_DISABLE, 0);
}

static void key_job_calibrate(void)
{
	key_calibrate(GKT_KEYPAD_CALIBRATE_ACTIVE);
}

int gkt_key_wakeup_resume_parameter(void)
{
	int retval;
	uint32_t value;
	
	gkt_keypad_control(GKT_KEYPAD_CTRL_ENABLE, 0);

	g_key_manage.flags &= ~KEY_F_CALIBRATE_DONE;

	g_key_manage.flags |= KEY_F_CALIBRATE_BUSY;
	retval = gkt_keypad_calibrate(0, GKT_KEYPAD_CALIBRATE_ACTIVE);
	g_key_manage.flags &= ~KEY_F_CALIBRATE_BUSY;

	if (GKT_SUCCESS == retval) {
		g_key_manage.flags |= KEY_F_CALIBRATE_DONE;
		key_calibrate_fail = 0;
	}
	else
		key_calibrate_fail = 1;

	G_BPK_ReadKey(&value, 1, GKT_RETMEM_KEYPAD);
	value &= 0xFFFF00FF;
	value |= key_calibrate_fail << 8;	
	G_BPK_WriteKey(&value, 1, GKT_RETMEM_KEYPAD);
	gkt_keypad_control(GKT_KEYPAD_CTRL_DISABLE, 0);

	return GKT_SUCCESS;
}

int gkt_key_calibrate(int force, uint32_t status)
{
	int retval;

	if (!(g_key_manage.flags & KEY_F_CALIBRATE_DONE) || force) {
		key_calibrate(status);
		retval = (g_key_manage.flags & KEY_F_CALIBRATE_DONE) ? 
						GKT_SUCCESS : -1;
	}
	else
		retval = GKT_SUCCESS;

	return retval;
}

#ifdef GKT_CONFIG_KEYPAD_SENSITIVE_SCAN_STANDBY_ATTR_TABLE	
int gkt_key_parameter_update(uint32_t response)
{
	gkt_keypad_parameter_update(response);
	return GKT_SUCCESS;
}
#endif

int gkt_key_init(void)
{
	gkt_keypad_config_params_s cfg_params;
	uint32_t channel, key, value;
	int retval;

	g_key_manage.flags = 0;
	g_key_manage.unmask_bits = (1U << GKT_KEY_MAX) - 1;
	g_key_manage.all_on_counter = 0;
	g_key_manage.wakeup_key = ~0;

	/* key default handlers */
	for (key = 0; key < GKT_KEY_MAX; key++)
		g_key_manage.def_handlers[key] = NULL;
	g_key_manage.def_handlers[GKT_KEY_RETURN] = key_RETURN_def_handler;

	if (GKT_SYSTEM_RESET_WAKEUP == g_system_info.reset_mode) {
#if defined(GKT_CONFIG_KEYPAD_SPT5115S_ENABLE) && GKT_CONFIG_KEYPAD_SPT5115S_ENABLE
		if (gkt_wakeup_get_source() == GKT_WAKEUP_SRC_keypad) {
			channel = gkt_keypad_get_wakeup_channel();
			g_key_manage.wakeup_key = channel_2_key(channel);
			gkt_printf("key_init: wakeup key = %u\n", g_key_manage.wakeup_key);
		}
#else
		uint32_t wakeup_pin;
		wakeup_pin = gkt_wkio_get_wakeup_pin();
		if ((wakeup_pin >= GKT_WKIO_PINNUMS))
		{
			gkt_wakeup_set_source(GKT_WAKEUP_SRC_keypad);

			channel = gkt_keypad_get_wakeup_channel();
			g_key_manage.wakeup_key = channel_2_key(channel);
			gkt_info("key_init: wakeup key = %u\n", g_key_manage.wakeup_key);
		}
#endif		
	}

	key_led_init();
	key_voice_init();

	cfg_params.debounce_time = GKT_KEY_DEBOUNCE_TIME;
	cfg_params.long_press_time = GKT_KEY_LONG_PRESS_TIME;
	cfg_params.repeat_interval = GKT_KEY_REPEAT_TIME;
	cfg_params.notify = key_notify;
	retval = gkt_keypad_config(&cfg_params);
	if (retval != GKT_SUCCESS) {
		gkt_error("key_init: config keypad failed %d\n", retval);
		return retval;
	}
	gkt_keypad_control(GKT_KEYPAD_CTRL_DISABLE, 0);

#if defined(GKT_CONFIG_KEY_INIT_LED_ALL_ON) && GKT_CONFIG_KEY_INIT_LED_ALL_ON
	gkt_key_led_control(GKT_KEY_LED_CTRL_BRIGHT, ~0);
#endif
	gkt_key_led_control(GKT_KEY_LED_CTRL_ENABLE, 1);

	if (GKT_SYSTEM_RESET_WAKEUP == g_system_info.reset_mode) {
		G_BPK_ReadKey(&value, 1, GKT_RETMEM_KEYPAD);
		key_calibrate_fail = (value >> 8) & 0xff;
	}
	
	/* key calibrate bg_job */
#if defined(GKT_CONFIG_SLIDING_CLOSURE_ENABLE) \
	&& GKT_CONFIG_SLIDING_CLOSURE_ENABLE	
	gkt_bg_job_register(GKT_BG_JOB_ID(key_job_calibrate), key_job_calibrate);
	gkt_bg_job_start(GKT_BG_JOB_ID(key_job_calibrate), GKT_BG_JOB_PRIORITY_MEDIUM);
#else
	if ((GKT_SYSTEM_RESET_HARD == g_system_info.reset_mode)
		|| (GKT_SYSTEM_RESET_SOFT == g_system_info.reset_mode)
		|| (GKT_SYSTEM_RESET_WTD == g_system_info.reset_mode)
		|| (key_calibrate_fail == 1)) {
		gkt_bg_job_register(GKT_BG_JOB_ID(key_job_calibrate), key_job_calibrate);
		gkt_bg_job_start(GKT_BG_JOB_ID(key_job_calibrate), GKT_BG_JOB_PRIORITY_MEDIUM);
	}
	else {
#if defined(GKT_CONFIG_KEY_WAKEUP_NO_CALIBRATE) && GKT_CONFIG_KEY_WAKEUP_NO_CALIBRATE	
		if (GKT_WAKEUP_SRC_keypad == gkt_wakeup_get_source())
			gkt_key_wakeup_resume_parameter();
		else {
			gkt_bg_job_register(GKT_BG_JOB_ID(key_job_calibrate), key_job_calibrate);
			gkt_bg_job_start(GKT_BG_JOB_ID(key_job_calibrate), GKT_BG_JOB_PRIORITY_MEDIUM);
		}
#else 
		gkt_bg_job_register(GKT_BG_JOB_ID(key_job_calibrate), key_job_calibrate);
		gkt_bg_job_start(GKT_BG_JOB_ID(key_job_calibrate), GKT_BG_JOB_PRIORITY_MEDIUM);
				
#endif		
	}
#endif

	return GKT_SUCCESS;	
}
GKT_EVENT_DESC_DEFINE(KEY, key);

uint32_t gkt_key_wakeup(void)
{
	return g_key_manage.wakeup_key;
}

void gkt_key_enable_long_press(uint32_t bits)
{
	g_key_manage.long_press_bits |= bits;
}
void gkt_key_disable_long_press(uint32_t bits)
{
	g_key_manage.long_press_bits &= ~bits;
}
#endif

